##parameters=assessmentIdentity, form
##title=processes embedded components forms values

# This script is somewhat of a hack- it has a lot of special cases for each component. In reality we need to optimize the API
# So that oldValue and newValue are in the same format (i.e. always entity objects, instead of sometimes identities)


from Products.KnowledgeEngine.Utils.helpers import objectType, makeList # Utility to wrap an object in a list if it isn't already

ass = context.knowledgeengine_assessmentstorageservice

# Load the assessment
assessment = ass.loadAssessment( assessmentIdentity )
if not assessment:
    return False

# Get all the available components from the model
model      = assessment.getModel()
components = model.getDescendantsByInstanceOf("Component")

changeLog = "" # Keep a record of changes we make. Returned at end of script

# Iterate over the components, updating each if they are specified in the form
# (As the form most likely contains values that don't represent a component, we don't just read it's keys)
for component in components:
    componentIdentity = component.getIdentity()
        
    # Was the component specified in the form?
    if componentIdentity in form:
        
        vocab = []
        
        if hasattr( component.aq_explicit, 'getVocab' ):
            vocab = dict(component.getVocab())

        
        oldValue = oldTitle = assessment.getComponentByIdentityValue( componentIdentity )
        newValue = newTitle = form[componentIdentity]
        
        if vocab:
            oldTitle = vocab.get( oldValue, None ) or oldValue
            newTitle = vocab.get( newValue, None ) or newValue
            
            
        
        # Hack - Convert booleans to the lowercase string representation. This allows Boolean types to work correctly
        if oldValue in (True, False):
            oldValue = oldTitle = str(oldValue).lower()
            
        
        # Force numeric boxes to a float.
        if component.isInstanceOf("NumericBox"):    
            oldValue = float(oldValue or 0.0)
            try: newValue = float(newValue or 0.0)
            except ValueError:
                newValue = newTitle = 0.00
            
         
       
        # Value hasn't changed so ignore this item
        if str(oldValue) == str(newValue):
            continue
        
        # Hack - We need to handly EC's slightly differently
        if component.isInstanceOf('EntityChooser'):
    
            newEntities = [component.getEntity(value) for value in makeList(newValue)]
        
            if oldValue: oldTitle = ", ".join( [value.getTitle() for value in makeList(oldValue)] )
            if newEntities: newTitle = ", ".join( [value.getTitle() for value in makeList(newEntities)] ) 
           
            if [str(x) for x in makeList(oldValue)] == [str(x) for x in makeList(newValue)]:
                continue # Entities havn't changed, skip
                         
        # Hack - handle FileUpload components differently.                         
        elif component.isInstanceOf('FileUpload'):

            if not newValue: continue
           
            tmpFilename, meta_type, filename, size = oldValue.split(',')
            oldTitle = filename
            newTitle = newValue.filename
            
        
        updatedValue = component.updateAssessmentState( assessment, newValue )
        
        component_title = ( component.getContent() or component.title_or_id() )
        
        # Python scripts recalculate behing the scenes when we call updateAssessmentState(). 
        # In this case, we want to get the new value it calculates and disregard the value entered on the form
        if component.isInstanceOf('PythonScript'):
            newTitle = updatedValue
        
        if component.isInstanceOf("Checkbox"):
            if newTitle   == 'true':  changeLog += "Enabled '%s'\n"  % component_title
            elif newTitle == 'false': changeLog += "Disabled '%s'\n" % component_title
                
        elif component.isInstanceOf("Option"):
            selection = component.aq_parent # Get the parent Selection question
            component_title = (selection.getContent() or selection.title_or_id())
            option_title    = (component.getContent() or component.title_or_id())
            
            if selection.getDisplayFormat() in ('Check Boxes', 'Multi Select List'):
                if newTitle == 'true': changeLog += "Selected   '%s' option '%s'\n" % ( component_title, option_title )
                else:                  changeLog += "Deselected '%s' option '%s'\n" % ( component_title, option_title )
                    
            else:            
                if newTitle == 'true': changeLog += "Changed '%s' to '%s'\n" % ( component_title, option_title )
               
                
        elif component.isInstanceOf('Selection'):
            pass # Ignore selection questions, we process the option components individually above                
            
        else:
            changeLog += "Changed '%s' from '%s' to '%s'\n" % (component_title, oldTitle, newTitle )
        
        
        assessment.setIsModified(True)

# Save changes
if assessment.getIsModified():
    ass.saveAssessment( assessment )
    
repositoryIdentities = ass.getRepositoriesForAssessment(assessment)    
    
user = context.knowledgeengine_userproviderservice.getUser( context.REQUEST.AUTHENTICATED_USER.getId() )    
    
# Handle the 'onAfterSaveAssessmentInAnyRepository' event for the model
if model.isEventEnabled("onAfterSaveAssessmentInAnyRepository"):
    model.getEnabledEvent("onAfterSaveAssessmentInAnyRepository").execute(assessment, user)    
    
# Success!
return changeLog